﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using BusinessObjects;
using System.Diagnostics;
using System.Threading;
using YourWorldServer.GreenWorldEntitiesService;

namespace YourWorldServer
{
    public class EventsManager
    {
        private static EventsManager instance;

        private EventsManager()
        {
            PendingQuestsRepository.Instance.QuestCompletedEvent += this.QuestCompleted;
        }

        public static EventsManager Instance
        {
            get
            {
                if ( instance == null )
                    instance = new EventsManager();

                return instance;
            }
        }

        public void StartAnEvent( Payload payload, int bytesRead )
        {
            string xmlData = Encoding.UTF8.GetString( payload.Buffer, 1, bytesRead - 1 );
            XmlSerializer xmlSrl = new XmlSerializer( typeof( Event ) );
            StringReader stream = new StringReader( xmlData );

            Event gameEvent = xmlSrl.Deserialize( stream ) as Event;

            Game playerGame = GameManager.Instance.GetGame( gameEvent.MapId );
            Player sender = playerGame.Players.Where( x => x.Id == gameEvent.PlayerId ).FirstOrDefault();

            Debug.Assert( sender != null, "There is no player with Id - " + gameEvent.PlayerId );

            if ( gameEvent.IsSingleInitiated == true )
            {
                sender.Quests = String.Format( "{0}, {1}", sender.Quests, gameEvent.Id );
                sender.QuestsCollection.Add( gameEvent );
                this.StartSingleQuest( gameEvent, playerGame );
            }
            else
            {
                PendingQuestsRepository.Instance.JoinQuest( sender, gameEvent );
            }
        }

        public void QuestCompleted( TeamEvent quest )
        {
            if ( quest.Quest.IsBuild == true )
            {
                this.SendBuildTeamQuestUpdateRequest( quest, quest.Quest.PlayerId );
                return;
            }

            PendingQuestsRepository.Instance.RemoveQuest( quest.Quest.MapId, quest.Quest.Id );

            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( TeamEvent ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, quest );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.QuestCompleted;
            xmlMessage.CopyTo( message, 1 );

            foreach ( Player player in quest.Members )
            {
                //send:
                Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( player.Id );
                ps.Write( message, 0, message.Length );
            }
        }

        public void ReceiveEventFeedBack( Payload payload, int bytesRead )
        {
            string xmlData = Encoding.UTF8.GetString( payload.Buffer, 1, bytesRead - 1 );
            XmlSerializer xmlSrl = new XmlSerializer( typeof( EventFeedback ) );
            StringReader stream = new StringReader( xmlData );

            EventFeedback gameEvent = xmlSrl.Deserialize( stream ) as EventFeedback;

            int eventOwnerId = gameEvent.GameEvent.PlayerId;
            Stream owner = GameManager.Instance.GetPlayerCommunicationChannel( eventOwnerId );

            // send to the event owner:
            owner.Write( payload.Buffer, 0, bytesRead );
        }

        public void BuildQuestUpdate( Payload payload, int bytesRead )
        {
            string xmlData = Encoding.UTF8.GetString( payload.Buffer, 1, bytesRead - 1 );
            XmlSerializer xmlSrl = new XmlSerializer( typeof( BuildQuestUpdateHolder ) );
            StringReader stream = new StringReader( xmlData );

            BuildQuestUpdateHolder update = xmlSrl.Deserialize( stream ) as BuildQuestUpdateHolder;

            Game playerGame = GameManager.Instance.GetGame( update.MapId );
            GameManager.Instance.AddQuestToMap( update.RegionObject.X, update.RegionObject.Y, update.QuestId, playerGame );

            Debug.Assert( playerGame != null, "There is no map with Id - " + update.MapId );

            TeamEvent quest = PendingQuestsRepository.Instance.GetQuest( update.MapId, update.QuestId, update.PlayerId );
            if ( quest != null )
            {
                PendingQuestsRepository.Instance.RemoveQuest( update.MapId, update.QuestId );
                // this was a team quest -SendBuildTeamQuestUpdateRequest- Response
                // send it to the other players so that they can update their maps

                quest.RegionObject = update.RegionObject;

                XmlSerializer xmlGameSrl = new XmlSerializer( typeof( TeamEvent ) );
                StringWriter textWriter = new StringWriter();

                xmlGameSrl.Serialize( textWriter, quest );
                string xml = textWriter.ToString();

                byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
                byte[] message = new byte[xmlMessage.Length + 1];

                message[0] = ( byte )SocketMessageKeys.QuestCompleted;
                xmlMessage.CopyTo( message, 1 );

                foreach ( Player player in quest.Members )
                {
                    if ( player.Id == update.PlayerId )
                        continue;

                    Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( player.Id );
                    ps.Write( message, 0, message.Length );
                }
            }
            else
            {
                // this was a single build -SendBuildQuestUpdateRequest- Response
                // send it to the other players so that they can update their maps
                foreach ( Player player in playerGame.Players )
                {
                    if ( player.Id == update.PlayerId )
                        continue;

                    Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( player.Id );
                    ps.Write( payload.Buffer, 0, bytesRead );
                }
            }
        }

        private void SendSupportEventRequest( Event gameEvent, int playerId )
        {
            // format:
            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( Event ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, gameEvent );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.SupportEventRequest;
            xmlMessage.CopyTo( message, 1 );

            //send:
            Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( playerId );
            ps.Write( message, 0, message.Length );
        }

        private void SendJoinEventRequest( Event gameEvent, int playerId )
        {
            // format:
            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( Event ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, gameEvent );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.JoinEventRequest;
            xmlMessage.CopyTo( message, 1 );

            //send:
            Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( playerId );
            ps.Write( message, 0, message.Length );
        }

        public void BadgeWonUpdate( Payload payload, int bytesRead )
        {
            string xmlData = Encoding.UTF8.GetString( payload.Buffer, 1, bytesRead - 1 );
            XmlSerializer xmlSrl = new XmlSerializer( typeof( BadgeUpdateHolder ) );
            StringReader stream = new StringReader( xmlData );

            BadgeUpdateHolder update = xmlSrl.Deserialize( stream ) as BadgeUpdateHolder;

            Game playerGame = GameManager.Instance.GetGame( update.MapId );
            Debug.Assert( playerGame != null, "There is no map with Id - " + update.MapId );
            Stream ps;

            foreach ( Player player in playerGame.Players )
            {
                if ( player.Id == update.PlayerId )
                {
                    player.Badges = String.Format( "{0},{1}", update.BadgeId, player.Badges );
                }
                else
                {
                    ps = GameManager.Instance.GetPlayerCommunicationChannel( player.Id );
                    ps.Write( payload.Buffer, 0, bytesRead );
                }
            }
        }

        private void StartSingleQuest( Event quest, Game playerGame )
        {
            if ( quest.IsBuild == true )
            {
                // send build quest request - the owner should decide where he wants to build it
                this.SendBuildQuestUpdateRequest( quest, quest.PlayerId );
                return;
            }

            BuildQuestUpdateHolder update = new BuildQuestUpdateHolder()
            {
                MapId = quest.MapId,
                PlayerId = quest.PlayerId,
                QuestId = quest.Id
            };

            // format:
            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( BuildQuestUpdateHolder ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, update );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.BuildQuestUpdate;
            xmlMessage.CopyTo( message, 1 );

            //send:
            foreach ( Player player in playerGame.Players )
            {
                Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( player.Id );
                ps.Write( message, 0, message.Length );
            }
        }

        private void SendBuildQuestUpdateRequest( Event gameEvent, int targetPlayerId )
        {
            Game playerGame = GameManager.Instance.GetGame( gameEvent.MapId );
            Player sender = playerGame.Players.Where( x => x.Id == targetPlayerId ).FirstOrDefault();

            Debug.Assert( sender != null, "There is no player with Id - " + targetPlayerId );

            // format:
            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( Event ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, gameEvent );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.BuildQuestUpdateRequest;
            xmlMessage.CopyTo( message, 1 );

            //send:
            Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( targetPlayerId );
            ps.Write( message, 0, message.Length );
        }

        private void SendBuildTeamQuestUpdateRequest( TeamEvent gameEvent, int targetPlayerId )
        {
            Game playerGame = GameManager.Instance.GetGame( gameEvent.Quest.MapId );
            Player sender = playerGame.Players.Where( x => x.Id == targetPlayerId ).FirstOrDefault();

            Debug.Assert( sender != null, "There is no player with Id - " + targetPlayerId );

            // format:
            XmlSerializer xmlGameSrl = new XmlSerializer( typeof( TeamEvent ) );
            StringWriter textWriter = new StringWriter();

            xmlGameSrl.Serialize( textWriter, gameEvent );
            string xml = textWriter.ToString();

            byte[] xmlMessage = Encoding.UTF8.GetBytes( xml );
            byte[] message = new byte[xmlMessage.Length + 1];

            message[0] = ( byte )SocketMessageKeys.BuildTeamQuestUpdateRequest;
            xmlMessage.CopyTo( message, 1 );

            //send:
            Stream ps = GameManager.Instance.GetPlayerCommunicationChannel( targetPlayerId );
            ps.Write( message, 0, message.Length );
        }

        private void StartTeamQuest()
        {
        }
    }
}
